cmake_minimum_required(VERSION 3.19.0)
if (USE_OBR_LIB)
    project(LibOptixBasedRenderer VERSION 0.1.0 LANGUAGES CUDA CXX)
    set(OBR_TARGET LibOptixBasedRenderer)
else()
    project(OptixBasedRenderer VERSION 0.1.0 LANGUAGES CUDA CXX)
    set(OBR_TARGET OptixBasedRenderer)
endif()

# for visual studio
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
file(GLOB_RECURSE _source_list *.c* *.cpp* *.h* *.hpp* *.cu* *.cuh* )
foreach(_source IN ITEMS ${_source_list})
    get_filename_component(_source_path "${_source}" PATH)
    string(REPLACE "${CMAKE_CURRENT_SOURCE_DIR}" "" _group_path "${_source_path}")
    string(REPLACE "/" "\\" _group_path "${_group_path}")
    source_group("${_group_path}" FILES "${_source}")
endforeach()

# custom dir variables
# set(VCPKG_INCLUDE_DIR "C:/dev/vcpkg/installed/x64-windows/include")
# set(CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES "C:/Program Files/NVIDIA GPU Computing Toolkit/CUDA/v11.3/include")
set(OptiX_INSTALL_DIR "C:/ProgramData/NVIDIA Corporation/OptiX SDK 7.3.0" CACHE PATH "Path to OptiX installed location.")

# add OpenMP support for cpu parallel
FIND_PACKAGE(OpenMP)
if(OPENMP_FOUND)
    message("---- OPENMP FOUND ----")
    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") 
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
    set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}")
endif()


# compile settings
# disable warning C4819
add_compile_options("$<$<COMPILE_LANGUAGE:CXX>:/wd4819>")
add_compile_options("$<$<COMPILE_LANGUAGE:CXX>:/wd4005>")
# add cuda compile options
add_compile_options("$<$<COMPILE_LANGUAGE:CUDA>:-G>")
add_compile_options("$<$<COMPILE_LANGUAGE:CUDA>:-use_fast_math>")
# diable RDC when using lib: NOTE: I dont know why
if (USE_OBR_LIB)
    add_compile_options("$<$<COMPILE_LANGUAGE:CUDA>:-rdc=false>")
endif()


# add cuda package
# SET(CUDA_SEPARABLE_COMPILATION ON)
find_package(CUDAToolkit 11.1 REQUIRED)
message("${CUDAToolkit_INCLUDE_DIRS}")


# add optix package
set(
    CMAKE_MODULE_PATH
    "${OptiX_INSTALL_DIR}/SDK/CMake"
    "${CMAKE_MODULE_PATH}"
)
find_package(OptiX REQUIRED)


# add vcpkg packages
find_package(OpenCV CONFIG REQUIRED)
find_package(imgui REQUIRED)
find_package(jsoncpp REQUIRED)
find_path(TINYGLTF_INCLUDE_DIRS "tiny_gltf.h")


# config cmake generated file
#! note: this should be synced with following include_directories
set(SHADER_INCLUDE_DIRS
    "${CMAKE_CURRENT_SOURCE_DIR}"
    "${CMAKE_CURRENT_SOURCE_DIR}/src"
    "${CMAKE_CURRENT_SOURCE_DIR}/include"
    "${OptiX_INSTALL_DIR}/include"
    "${CUDAToolkit_INCLUDE_DIRS}"
)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/include/CompileConfig.h.cmakeinput ${CMAKE_CURRENT_SOURCE_DIR}/include/CompileConfig.h)



# cpp proj files
file(GLOB_RECURSE PROJ_CPP_SOURCES_INCLUDE "${CMAKE_CURRENT_SOURCE_DIR}/include/*.cpp")
file(GLOB_RECURSE PROJ_C_SOURCES_INCLUDE "${CMAKE_CURRENT_SOURCE_DIR}/include/*.c")
if (USE_OBR_LIB)
    file(GLOB_RECURSE PROJ_CPP_SOURCES_SRC "${CMAKE_CURRENT_SOURCE_DIR}/src/*/*.cpp")
    file(GLOB_RECURSE PROJ_C_SOURCES_SRC "${CMAKE_CURRENT_SOURCE_DIR}/src/*/*.c")
else()
    file(GLOB_RECURSE PROJ_CPP_SOURCES_SRC "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp")
    file(GLOB_RECURSE PROJ_C_SOURCES_SRC "${CMAKE_CURRENT_SOURCE_DIR}/src/*.c")
endif()
set(
    PROJ_SOURCE_FILES
    ${PROJ_CPP_SOURCES_INCLUDE}
    ${PROJ_C_SOURCES_INCLUDE}
    ${PROJ_CPP_SOURCES_SRC}
    ${PROJ_C_SOURCES_SRC}
)
message("source files: " ${PROJ_SOURCE_FILES})

# cuda files (shaders are compiled JIT but others need to be compiled AOT)
file(GLOB_RECURSE PROJ_CUDA_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cu")
set(
    PROJ_CUDA_FILES
    ${PROJ_CUDA_SOURCES}
)
message("cuda files: " ${PROJ_CUDA_FILES})


file(GLOB_RECURSE PROJ_CUDA_SHADER_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/shaders/*.cu")
file(GLOB_RECURSE PROJ_CUDA_SHADER_HEADERS "${CMAKE_CURRENT_SOURCE_DIR}/shaders/*.cuh")


# create exe / lib
if (USE_OBR_LIB)
    list(REMOVE_ITEM PROJ_SOURCE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/src/main.cpp")
    add_library(
        LibOptixBasedRenderer
        ${PROJ_SOURCE_FILES}
        ${PROJ_CUDA_FILES}
    )
else()
    add_executable(
        OptixBasedRenderer
        ${PROJ_SOURCE_FILES}
        ${PROJ_CUDA_FILES}
    )
endif()


# target properties
set_target_properties(
        ${OBR_TARGET} 
        PROPERTIES 
        CXX_STANDARD 20)
set_target_properties(
        ${OBR_TARGET}
        PROPERTIES
        CUDA_SEPARABLE_COMPILATION ON)

# link to libs
target_link_libraries(${OBR_TARGET} ${CUDA_LIBRARIES})
target_link_libraries(${OBR_TARGET} CUDA::cudart)
target_link_libraries(${OBR_TARGET} CUDA::nvrtc)
target_link_libraries(${OBR_TARGET} jsoncpp_lib jsoncpp_object)
target_link_libraries(${OBR_TARGET} ${OpenCV_LIBRARIES})
target_link_libraries(${OBR_TARGET} imgui::imgui)

# custom relatively include dir
#! note: this should be synced with ${REL_INCLUDE_DIRS}
target_include_directories(${OBR_TARGET} PUBLIC "${CUDAToolkit_INCLUDE_DIRS}")
target_include_directories(${OBR_TARGET} PUBLIC "${OptiX_INSTALL_DIR}/include")
target_include_directories(${OBR_TARGET} PUBLIC "${TINYGLTF_INCLUDE_DIRS}")
target_include_directories(${OBR_TARGET} PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/")
target_include_directories(${OBR_TARGET} PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/src")
target_include_directories(${OBR_TARGET} PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include")

set_target_properties(${OBR_TARGET} 
    PROPERTIES 
    PUBLIC_HEADER 
    "${PROJ_CPP_HEADERS_SRC} ${PROJ_CPP_HEADERS_INCLUDE}"
)
# get_cmake_property(_variableNames VARIABLES)
# list (SORT _variableNames)
# foreach (_variableName ${_variableNames})
#     message(STATUS "${_variableName}=${${_variableName}}")
# endforeach()
